/*
 * Copyright (c) 2025 Industrial Software Feature Database
 */
package com.comac.ins.isfd.service.impl;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.io.FileInputStream;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.hutool.core.collection.CollectionUtil;
import com.anwen.mongo.conditions.query.LambdaQueryChainWrapper;
import com.anwen.mongo.conditions.update.LambdaUpdateChainWrapper;
import com.anwen.mongo.model.PageResult;
import com.anwen.mongo.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.comac.ins.common.core.domain.model.LoginUser;
import com.comac.ins.common.core.exception.ServiceException;
import com.comac.ins.common.core.exception.base.BaseException;
import com.comac.ins.common.core.utils.MapstructUtils;
import com.comac.ins.common.encrypt.utils.EncryptUtils;
import com.comac.ins.common.excel.utils.ExcelUtil;
import com.comac.ins.common.mybatis.core.page.TableDataInfo;
import com.comac.ins.isfd.domain.IsfdRegionLibraryMongo;
import com.comac.ins.isfd.domain.bo.query.IsfdRegionLibraryQueryBo;
import com.comac.ins.isfd.domain.vo.IsfdRegionLibraryMongoVo;
import com.comac.ins.isfd.mapper.IsfdRegionLibraryMongoMapper;
import com.comac.ins.isfd.service.IIsfdRegionLibraryMongoService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 【请填写功能名称】Service业务层处理
 *
 * @author wujialin
 * @date 2025-06-08
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class IsfdRegionLibraryMongoServiceImpl extends ServiceImpl<IsfdRegionLibraryMongo> implements IIsfdRegionLibraryMongoService {

    @Autowired
    private IsfdRegionLibraryMongoMapper baseMapper;

    /**
     * 查询【请填写功能名称】
     *
     * @param id 主键
     * @return 【请填写功能名称】
     */
    @Override
    public IsfdRegionLibraryMongoVo queryById(String id) {
        // 根据主键查询实体
        IsfdRegionLibraryMongo entity = this.lambdaQuery()
            .eq(IsfdRegionLibraryMongo::get_id, id)
            .one();
        if (Objects.nonNull(entity)) {
            // 转换为VO对象
            IsfdRegionLibraryMongoVo vo = MapstructUtils.convert(entity, IsfdRegionLibraryMongoVo.class);
            return vo;
        }
        return null;
    }

    /**
     * 分页查询【请填写功能名称】列表
     *
     * @param bo 查询条件
     * @return 【请填写功能名称】分页列表
     */
    @Override
    public TableDataInfo<IsfdRegionLibraryMongoVo> queryPageList(IsfdRegionLibraryQueryBo bo) {
        // 构造返回列表
        List<IsfdRegionLibraryMongo> regionLibraryMongoList = new ArrayList<>();
        Integer pageNum = bo.getPageNum();
        Integer pageSize = bo.getPageSize();

        // 构造查询参数
        LambdaQueryChainWrapper<IsfdRegionLibraryMongo> queryChainWrapper = this.lambdaQuery();
        queryChainWrapper
            .like(StringUtils.isNotBlank(bo.getRegionCode()), IsfdRegionLibraryMongo::getRegionCode, bo.getRegionCode())
            .like(StringUtils.isNotBlank(bo.getRegionType()), IsfdRegionLibraryMongo::getRegionType, bo.getRegionType())
            .in(CollectionUtil.isNotEmpty(bo.getIdList()), IsfdRegionLibraryMongo::get_id, bo.getIdList())
            .orderByDesc(IsfdRegionLibraryMongo::getCreateTime);

        // Mongo 分页查询
        PageResult<IsfdRegionLibraryMongo> page = this.page(queryChainWrapper, pageNum, pageSize);
        List<IsfdRegionLibraryMongo> contentData = page.getContentData();
        regionLibraryMongoList.addAll(contentData);
        Long total = page.getTotalSize();

        // 空集直接返回
        if (CollectionUtil.isEmpty(regionLibraryMongoList)) {
            return TableDataInfo.build();
        }

        // 转换成VO
        List<IsfdRegionLibraryMongoVo> voList = MapstructUtils.convert(regionLibraryMongoList, IsfdRegionLibraryMongoVo.class);

        return TableDataInfo.buildToPageMemoryLimit(Boolean.FALSE, voList, pageNum, pageSize, total);
    }

    @Transactional
    @Override
    public Boolean save(IsfdRegionLibraryMongoVo vo, LoginUser loginUser) {
        // 1. 参数校验
        checkParams(vo);

        // 2. 获取 hash 字段
        String hashUniqueKey = EncryptUtils.hashFields(
            vo.getRegionCode(),
            vo.getRegionType(),
            vo.getShape(),
            vo.getDimensions(),
            vo.getBoundaryCondition(),
            vo.getConstructionMethod(),
            vo.getCoordinateData()
        );

        // 3. 幂等校验（是否已存在，存在则为更新）
        boolean isUpdate = checkUnique(vo, hashUniqueKey);

        // 4. 设置字段并落表
        IsfdRegionLibraryMongo entity = new IsfdRegionLibraryMongo();
        vo.setHashUniqueKey(hashUniqueKey);
        vo.setUpdateBy(String.valueOf(loginUser.getUserId()));
        vo.setUpdateTime(new Date().toString());

        if (!isUpdate) {
            vo.setCreateBy(String.valueOf(loginUser.getUserId()));
            vo.setCreateTime(new Date().toString());
        }

        BeanUtils.copyProperties(vo, entity);
        this.saveOrUpdate(entity);
        return Boolean.TRUE;
    }

    private void checkParams(IsfdRegionLibraryMongoVo vo) {
        if (StringUtils.isBlank(vo.getRegionCode())) {
            throw new ServiceException("区域编码不能为空");
        }
        if (StringUtils.isBlank(vo.getRegionType())) {
            throw new ServiceException("区域类型不能为空");
        }
    }

    @Override
    public Boolean checkUnique(IsfdRegionLibraryMongoVo vo, String hashUniqueKey) {
        Boolean isUpdate = Boolean.FALSE;
        String id = vo.get_id();

        if (!StringUtils.isNotEmpty(id)) {
            // 新增场景，查是否已有相同 hash 的数据
            IsfdRegionLibraryMongo existing = this.lambdaQuery()
                .eq(IsfdRegionLibraryMongo::getHashUniqueKey, hashUniqueKey)
                .one();
            if (existing != null) {
                throw new BaseException("已经存在相同区域属性数据，不可重复存入，请确认入参后重试！");
            }
        } else {
            // 修改场景，校验当前数据是否存在
            IsfdRegionLibraryMongoVo dbVo = queryById(id);
            if (Objects.isNull(dbVo)) {
                throw new BaseException("修改失败，数据不存在，请确认ID后重试！");
            }

            String dbHash = dbVo.getHashUniqueKey();
            if (hashUniqueKey.equals(dbHash)) {
                throw new BaseException("已经存在相同区域属性数据，不可重复存入，请确认入参后重试！");
            }

            isUpdate = Boolean.TRUE;
        }

        return isUpdate;
    }

    /**
     * 校验并批量删除区域信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid) {
        if (isValid) {
            // TODO 根据业务需要做有效性校验，例如是否被引用等
        }

        for (String id : ids) {
            // 查询区域数据并删除
            IsfdRegionLibraryMongoVo regionLibraryMongoVo = queryById(id);
            if (Objects.nonNull(regionLibraryMongoVo)) {
                LambdaUpdateChainWrapper<IsfdRegionLibraryMongo> updateChainWrapper = this.lambdaUpdate();
                updateChainWrapper.eq(IsfdRegionLibraryMongo::get_id, id);
                this.remove(updateChainWrapper);
            } else {
                throw new BaseException("删除失败，数据不存在，请确认id后重试！");
            }
        }
        return Boolean.TRUE;
    }

    @Override
    public void export(IsfdRegionLibraryQueryBo queryBo, HttpServletResponse response) {
        // 设定导出范围为全部数据
        queryBo.setPageNum(1);
        queryBo.setPageSize(999999999);
        TableDataInfo<IsfdRegionLibraryMongoVo> tableDataInfo = queryPageList(queryBo);
        List<IsfdRegionLibraryMongoVo> voList = tableDataInfo.getRows();

        // 构建表头
        List<String> headerList = new ArrayList<>();
        headerList.add("区域编码");
        headerList.add("区域类型");
        headerList.add("几何形状");
        headerList.add("几何尺寸");
        headerList.add("边界条件");
        headerList.add("构建方式");
        headerList.add("区域坐标数据");
        headerList.add("备注");

        // 构造数据列表
        List<Map<String, Object>> dataList = new ArrayList<>();
        for (IsfdRegionLibraryMongoVo vo : voList) {
            Map<String, Object> rowMap = new HashMap<>();
            rowMap.put("区域编码", vo.getRegionCode());
            rowMap.put("区域类型", vo.getRegionType());
            rowMap.put("几何形状", vo.getShape());
            rowMap.put("几何尺寸", vo.getDimensions());
            rowMap.put("边界条件", vo.getBoundaryCondition());
            rowMap.put("构建方式", vo.getConstructionMethod());
            rowMap.put("区域坐标数据", vo.getCoordinateData());
            rowMap.put("备注", vo.getRemarks());
            dataList.add(rowMap);
        }

        // 调用工具类导出
        ExcelUtil.exportExcelReBuildHeader("【区域库】", headerList, dataList, response);
    }

    @Override
    public void exportTemplate(HttpServletResponse response) {

        // 构建表头
        List<String> headerList = new ArrayList<>();
        headerList.add("区域编码");
        headerList.add("区域类型");
        headerList.add("几何形状");
        headerList.add("几何尺寸");
        headerList.add("边界条件");
        headerList.add("构建方式");
        headerList.add("区域坐标数据");
        headerList.add("备注");

        // 构造空数据列表
        List<Map<String, Object>> dataList = new ArrayList<>();

        // 调用工具类导出
        ExcelUtil.exportExcelReBuildHeader("【区域库】", headerList, dataList, response);
    }

    @Override
    public Long excelImport(File file, LoginUser loginUser) {
        long successCount = 0L;
        try (InputStream is = new FileInputStream(file)) {
            // 只处理 .xlsx 文件
            List<IsfdRegionLibraryMongoVo> importVoList = ExcelUtil.importExcel(is, IsfdRegionLibraryMongoVo.class);
            for (IsfdRegionLibraryMongoVo vo : importVoList) {
                try {
                    this.save(vo, loginUser);
                    successCount++;
                } catch (Exception e) {
                    log.error("区域库数据导入失败", e);
                }
            }
        } catch (Exception e) {
            log.error("区域库导入失败", e);
            throw new BaseException("区域库导入失败：" + e.getMessage());
        }
        return successCount;
    }


}
